#include "ActionCancelPurchaseReq.h"
#include "json.h"
#include "util.h"
#include "streamdata.h"
#include "agencyevent.h"
#include "agencyeventmgr.h"
#include "agency_event_service.h"
#include "flow_service.h"
#include "api_order_service.h"
#include "9200_agency_event_api.pb.h"
#include "3400_api_order.pb.h"
#include <unordered_set>


static std::map<std::string,std::string> http_json_heads = {{"Content-Type","application/json"}};

static bool __init__ = ActionCancelPurchaseReq::Init();

bool ActionCancelPurchaseReq::Init()
{
    Ctx.msg_router.BindMsg(agency_event_api::AGENCY_EVENT_API_MSGID_CANCEL_PURCHASE_REQ, ActionCancelPurchaseReq::HandleCancelPurchaseReq);
    AgencyEventService::Instance()->ListenOnAgencyEventGet(AgencyEventService::CANCELPURCHASE, ActionCancelPurchaseReq::OnAgencyGet);

    return true;
}

void ActionCancelPurchaseReq::HandleCancelPurchaseReq(MsgData&& msg_data)
{
    agency_event_api::CancelPurchaseReq req;
    agency_event_api::CancelPurchaseResp resp;

    do
    {
        if (!req.ParseFromArray(msg_data.data.data(), msg_data.data.size()))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
            log_error("parser msg failed uuid=%d;", msg_data.uuid);
            break;
        }

        // 检查参数值
        if(req.dest_order_list_size() > 50)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::InputParamErr);
            log_error("over limit, dest_order_list size > 50, dest_order_list size=%d;", req.dest_order_list_size());
            break;
        }
        // 批量撤销单去重
        auto* order_list = req.mutable_dest_order_list();
        const int size = order_list->size();
        if(size > 1)
        {
            std::unordered_set<std::uint64_t> seen;
            seen.reserve(size);
            int pos=0;
            for(int i=0; i<size; ++i)
            {
                std::uint64_t order_id = (*order_list)[i].order_id();
                if(seen.insert(order_id).second)
                {
                    (*order_list)[i].set_fee(-(*order_list)[i].fee());// fee取反
                    if(pos!=i)
                    {
                        order_list->SwapElements(pos, i);
                    }
                    ++pos;
                }
            }
            while(order_list->size() > pos)
            {
                order_list->RemoveLast();
            }
        }

        stAgencyEvent* agency = AgencyEventMgr::Instance()->Get(req.agency_id());
        if (agency != nullptr)
        {
            CancelPurchaseRegParam p;
            p.user_id = req.uid();
            p.username = req.username();
            p.agency_id = req.agency_id();
            p.game_id = req.game();
            p.balance = req.balance();
            p.order_id = req.order_id();
            p.scene_from = req.scene_from();

            p.dest_order_list.reserve(req.dest_order_list_size());
            for(const agency_event_api::PurchaseOrderInfo& temp : req.dest_order_list())
            {
                CancelPurchaseOrderInfo t;
                t.purchase_time = temp.purchase_time();
                t.order_id = temp.order_id();
                t.fee = temp.fee();
                t.cycle = temp.cycle();
                p.dest_order_list.push_back(t);
            }

            p.agency_name = agency->agency_name;
            p.currency = agency->currency;
            p.currency_unit_multi = agency->currency_unit_multi;
            
            // 发起请求
            Request(agency->call_url, req.trans(), 
                req.uid(), msg_data.svtype, msg_data.svid, msg_data.uuid, p);
        }
        else
        {
            // 获取代理商信息
            StreamData stream_data;
            StreamDataWriter writer(stream_data);
            writer.WriteShort(msg_data.svtype);
            writer.WriteInt(msg_data.svid);
            writer.WriteInt(msg_data.uuid);
            writer.WriteInt(req.uid());
            writer.WriteInt(msg_data.data.size());
            writer.WriteBinary(msg_data.data.data(), msg_data.data.size());
            
            if (!AgencyEventService::Instance()->HandleGetAgencyEvent(req.agency_id(), std::move(stream_data.Data()), AgencyEventService::CANCELPURCHASE))
            {
                resp.set_errorcode(agency_event_api::ErrorCode::AgentGetErr);
                log_error("HandleGetAgencyEvent parser msg failed");
                break;
            }
        }
        return;
    } while (false);
    
    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_message(ToString(resp.errorcode()));
        resp.set_uid(req.uid());
        resp.set_trans(req.trans());
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_CANCEL_PURCHASE_RESP, &resp, msg_data.svtype, msg_data.svid, false, msg_data.uuid);
    }
}

void ActionCancelPurchaseReq::OnAgencyGet(std::int32_t err_code, stAgencyEvent* agency, std::string&& trans)
{
    StreamData stream_data(std::move(trans));
    StreamDataReader reader(stream_data);
    std::uint16_t svtype = reader.ReadShort();
    std::uint32_t svid = reader.ReadInt();
    std::uint32_t uuid = reader.ReadInt();
    std::uint32_t uid = reader.ReadInt();
    std::string msg_data = reader.ReadString();

    agency_event_api::CancelPurchaseResp resp;
    do
    {
        if (err_code != 0)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
            log_error("get agencyevent info failed, uid:%u, err_code:%d;", uid, err_code);
            break;
        }
        if (agency == nullptr)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
            log_error("agencyevent is nullptr, uid:%u, err_code:%d;", uid, err_code);
            break;
        }

        agency_event_api::CancelPurchaseReq req;
        if(!req.ParseFromArray(msg_data.c_str(), msg_data.size()))
        {
            resp.set_errorcode(agency_event_api::DataParseErr);
            log_error("parser msg failed");
            break;
        }
        log_debug("agency:%s;", agency->ToString().c_str());

        CancelPurchaseRegParam p;
        p.user_id = req.uid();
        p.username = req.username();
        p.agency_id = req.agency_id();
        p.game_id = req.game();
        p.balance = req.balance();
        p.order_id = req.order_id();
        p.scene_from = req.scene_from();

        p.dest_order_list.reserve(req.dest_order_list_size());
        for(const agency_event_api::PurchaseOrderInfo& temp : req.dest_order_list())
        {
            CancelPurchaseOrderInfo t;
            t.purchase_time = temp.purchase_time();
            t.order_id = temp.order_id();
            t.fee = temp.fee();
            t.cycle = temp.cycle();
            p.dest_order_list.push_back(t);
        }

        p.agency_name = agency->agency_name;
        p.currency = agency->currency;
        p.currency_unit_multi = agency->currency_unit_multi;

        Request(agency->call_url, trans, p.user_id, svtype, svid, uuid, p);
        return;
    } while (false);
    
    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_message(ToString(resp.errorcode()));
        resp.set_uid(uid);
        resp.set_trans(std::move(trans));
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_PURCHASE_RESP, &resp, svtype, svid, false, uuid);
    }
}

void ActionCancelPurchaseReq::Request(const std::string& baseurl, const std::string& trans,std::uint32_t uid,
    std::uint16_t svtype, std::uint32_t svid, std::uint32_t uuid, const CancelPurchaseRegParam& params)
{

    agency_event_api::CancelPurchaseResp resp;
    do
    {
        if (params.currency_unit_multi == 0)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AbnormalErr);
            log_error("currency_unit_multi is 0, uid:%u, cancel_order_id:%lu, currency:%s;",uid, params.order_id, params.currency.c_str());
            break;
        }
        log_debug("agency_id=%u, currency_unit_multi=%ld;",params.agency_id, params.currency_unit_multi);

        std::string req_id = GenTransId();
        std::uint64_t now = CTools::GetUnixTime();

        Json::Value http_req;
        http_req["reqId"] = req_id;
        http_req["username"] = params.username;
        http_req["currency"] = params.currency;
        http_req["game"] = params.game_id;
        http_req["round"] = Json::UInt64(params.order_id);
        Json::Value order_list(Json::arrayValue);
        for(const auto& temp : params.dest_order_list)
        {
            Json::Value t;
            t["purchtime"] = Json::Int64(temp.purchase_time);
            t["orderid"] = Json::UInt64(temp.order_id);
            t["price"] = Json::Int64(temp.fee * 1.0 / params.currency_unit_multi);
            t["cycle"] = Json::UInt64(temp.cycle);
            order_list.append(t);
        }
        http_req["orderlist"] = order_list;

        std::string json_string = CTools::ToStr(http_req);
        std::string url = baseurl + "/cancelPurchase";

        api_order::ApiOrder api_order;
        api_order.set_scene_from(params.scene_from);
        api_order.set_stype_from(svtype);
        api_order.set_svid_from(svid);
        api_order.set_uid(uid);
        api_order.set_username(params.username);
        api_order.set_agency(params.agency_name);
        api_order.set_currency(params.currency);
        api_order.set_gameid(params.game_id);
        api_order.set_op(api_order::API_ORDER_OP_CANCLE_PURCHASE);
        api_order.set_url(url);
        api_order.set_req_id(req_id);
        api_order.set_req_body(json_string);
        api_order.set_start_time(now);
        api_order.set_update_time(now);
        api_order.set_balance(params.balance);

        std::uint32_t event_id = 0;
        // 请求http网络
        if (!Ctx.msg_router.sendHttpPOST(url, json_string, http_json_heads, event_id) || (event_id == 0))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::SendPostErr);
            log_error("net post failed, url:%s, param:%s;", url.c_str(), json_string.c_str());
            break;
        }
        log_debug("http post, url:%s, param:%s;", url.c_str(), json_string.c_str());
        
        // 添加回调监听
        Ctx.msg_router.AddCurlEvent(event_id, [uid, svtype, svid, uuid, req_trans=std::move(trans), params = params,
            url=std::move(url), json_string= std::move(json_string), api_order_v = std::move(api_order)](std::string& body, bool is_ok){
            
            agency_event_api::CancelPurchaseResp resp;
            Json::Value http_resp;
            
            std::uint64_t now = CTools::GetUnixTime();
            api_order::ApiOrder api_order = std::move(api_order_v);
            api_order.set_update_time(now);
            api_order.set_resp_body(body);
            do
            {
                if (!is_ok)
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::RespTimeout);
                    log_error("time out, url:%s, param:%s;", url.c_str(), json_string.c_str());
                    break;
                }
                
                // 解析返回格式
                if (!CTools::FromStr(http_resp, body))
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
                    log_error("resp from json failed, body:%s, url:%s, param:%s;", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                if (!http_resp.isMember("username") || !http_resp["username"].isString()
                    || !http_resp.isMember("currency") || !http_resp["currency"].isString() 
                    || !http_resp.isMember("balance") || !http_resp["balance"].isDouble()
                    || !http_resp.isMember("errorCode") || !http_resp["errorCode"].isInt()
                    || !http_resp.isMember("message") || !http_resp["message"].isString()
                    || !http_resp.isMember("faildorderlist") || !http_resp["faildorderlist"].isArray()
                    || !http_resp.isMember("successorderlist") || !http_resp["successorderlist"].isArray()
                )
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::InvaildParam);
                    log_error("response param invalid, body:%s, url:%s, param:%s;", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                for(const auto& temp : http_resp["successorderlist"])
                {
                    if(!temp.isMember("purchtime") || !temp["purchtime"].isInt64()) { log_error("purchtime is null or no int64! body:%s;", body.c_str()); return; }
                    if(!temp.isMember("orderid") || !temp["orderid"].isUInt64()) { log_error("orderid is null or no uint64! body:%s;", body.c_str()); return; }
                    if(!temp.isMember("price") || !temp["price"].isDouble()) { log_error("price is null or no double! body:%s;", body.c_str()); return; }
                    if(!temp.isMember("cycle") || !temp["cycle"].isUInt64()) { log_error("cycle is null or no uint64! body:%s;", body.c_str()); return; }
                }
                for(const auto& temp : http_resp["faildorderlist"])
                {
                    if(!temp.isMember("purchtime") || !temp["purchtime"].isInt64()) { log_error("purchtime is null or no int64! body:%s;", body.c_str()); return; }
                    if(!temp.isMember("orderid") || !temp["orderid"].isUInt64()) { log_error("orderid is null or no uint64! body:%s;", body.c_str()); return; }
                    if(!temp.isMember("price") || !temp["price"].isDouble()) { log_error("price is null or no double! body:%s;", body.c_str()); return; }
                    if(!temp.isMember("cycle") || !temp["cycle"].isUInt64()) { log_error("cycle is null or no uint64! body:%s;", body.c_str()); return; }
                }
            
                if (params.currency_unit_multi == 0)
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::AbnormalErr);
                    log_error("currency_unit_multi is 0, body:%s, url:%s, param:%s;", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                resp.set_errorcode(http_resp["errorCode"].asInt());
                resp.set_balance(http_resp["balance"].asDouble() * params.currency_unit_multi);
                
                std::int64_t txid = 0;
                if (http_resp.isMember("txId") && http_resp["txId"].isInt64()) 
                {
                    txid = http_resp["txId"].asInt64();
                }
                api_order.set_resp_id(txid);
                api_order.set_balance(resp.balance());
            } while (false);
            
            // 回包
            resp.set_message(ToString(resp.errorcode()));
            resp.set_uid(uid);
            resp.set_trans(std::move(req_trans));
            log_debug("resp:%s;", resp.ShortDebugString().c_str());

            Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_CANCEL_PURCHASE_RESP, &resp, svtype, svid, false, uuid);

            for(const auto& temp : http_resp["successorderlist"])
            {
                api_order.set_cycle(temp["cycle"].asUInt64());
                api_order.set_orderid(temp["orderid"].asUInt64());
                api_order.set_bet(temp["price"].asDouble() * 1.0 / params.currency_unit_multi);

                // 上报流水
                if (api_order.scene_from() == 0)
                {   
                    
                    FlowService::Instance()->OnCancelPurchaseReg(
                        resp.errorcode(), resp.balance(), GameProvider(), 
                        params.user_id, params.agency_id, params.game_id, api_order.cycle(), 
                        api_order.start_time(), api_order.bet(), temp["purchtime"].asInt64(), params.order_id, api_order.orderid()
                    );
                }

                // 订单更新
                api_order.set_err_code(resp.errorcode());
                ApiOrderService::Instance()->OnApiOrderUpdate(api_order);
            }
            for(const auto& temp : http_resp["faildorderlist"])
            {
                api_order.set_cycle(temp["cycle"].asUInt64());
                api_order.set_orderid(temp["orderid"].asUInt64());
                api_order.set_bet(temp["price"].asDouble() * 1.0 / params.currency_unit_multi);

                // 上报流水
                if (api_order.scene_from() == 0)
                {   
                    
                    FlowService::Instance()->OnCancelPurchaseReg(
                        resp.errorcode(), resp.balance(), GameProvider(), 
                        params.user_id, params.agency_id, params.game_id, api_order.cycle(), 
                        params.order_id, api_order.start_time(), api_order.bet(), temp["purchtime"].asInt64(), api_order.orderid()
                    );
                }

                // 订单更新
                api_order.set_err_code(resp.errorcode());
                ApiOrderService::Instance()->OnApiOrderUpdate(api_order);
            }
            

        });
        return;

    } while (false);

    if (resp.errorcode() != 0)
    {
        // 失败回包
        resp.set_message(ToString(resp.errorcode()));
        resp.set_uid(uid);
        resp.set_trans(std::move(trans));
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_PURCHASE_RESP, &resp, svtype, svid, false, uuid);
    }
}




